/*
 * Copyright (C) 2011 bus.fm
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.busfm.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.SocketTimeoutException;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.conn.ConnectTimeoutException;

import com.busfm.net.NetWorkHelper;

import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.widget.ImageView;

/**
 * <p>
 * Title:AsyncImageLoader
 * </p>
 * <p>
 * Description: AsyncImageLoader
 * </p>
 * <p>
 * Copyright (c) 2011 www.bus.fm Inc. All rights reserved.
 * </p>
 * <p>
 * Company: bus.fm
 * </p>
 * 
 * 
 * @author jingguo0@gmail.com
 * 
 */
public class AsyncImageLoader {
    private static final int RETRY_COUNT = 3;
    public static final String REGEXP_ICON = "(/{0,1}\\w){1,}\\.(gif|dmp|png|jpg|jpeg|bmp)$|\\w{1,}\\.(gif|dmp|png|jpg|jpeg|bmp)$";
    private static AsyncImageLoader asyncImageInstance = new AsyncImageLoader();
    private final ImageCache imageCache = new ImageCache();
    private onImageDownloadedListener mListener;

    public static interface onImageDownloadedListener {
        public void onImageDownloadedListener();

        public void onImageDownloadedFailedListener();
    }

    public static boolean isValidate(String source, String regexp) {
        boolean result = false;

        if (!Utilities.isEmpty(source) && !Utilities.isEmpty(regexp)) {
            Pattern pattern = Pattern.compile(regexp);
            Matcher matcher = pattern.matcher(source);

            if (matcher.find()) {
                result = true;
            }
        }

        return result;
    }

    public static AsyncImageLoader getInstance() {
        return asyncImageInstance;
    }

    public void loadImage(String url, ImageView imageView, int resId, onImageDownloadedListener listener) {
        mListener = listener;
        Bitmap bitmap = getBitmapFromCache(url);
        if (null != bitmap) {
            imageView.setImageBitmap(bitmap);
            listener.onImageDownloadedListener();
        } else {
            if (isValidate(url, REGEXP_ICON)) {
                BitmapDownloadTask task = new BitmapDownloadTask(imageView);
                task.execute(url);
            } else {
                imageView.setImageResource(resId);//default Cover
                listener.onImageDownloadedFailedListener();
            }
        }
    }

    public Bitmap loadImage(String url, int targetWidth, int targetHeight) {
        Bitmap coverImageBitmap = null;
        String filename = url.substring(url.lastIndexOf("/") + 1);

        if (Utilities.isEmpty(filename)) {
            return null;
        }

        String path = FileUtil.getCoverDir() + FileUtil.SEPARATOR + filename;
        File file = new File(path);

        if (!file.exists()) {
            download(url, file);
        }

        coverImageBitmap = ImageUtil.loadScalledBitmap(path, targetWidth, targetHeight);
        if (null != coverImageBitmap) {
            coverImageBitmap = ImageUtil.createReflectionImageWithOrigin(coverImageBitmap);
        }

        return coverImageBitmap;
    }

    private void download(String url, File file) {
        int retryCount = 0;
        BufferedInputStream bis = null;

        while (retryCount < RETRY_COUNT) {

            try {
                bis = NetWorkHelper.performRequest(url);
                byte[] bs = new byte[1 << 12];
                int len = -1;
                OutputStream os = new FileOutputStream(file);

                try {

                    while ((len = bis.read(bs)) != -1) {
                        os.write(bs, 0, len);
                    }

                    os.flush();
                    retryCount = RETRY_COUNT;
                } catch (Exception e) {
                    retryCount++;
                    LogUtil.e(Constants.TAG, e.getMessage());
                } finally {
                    if (null != os) {
                        os.close();
                    }

                    if (null != bis) {
                        bis.close();
                    }

                }

            } catch (SocketTimeoutException ste) {
                LogUtil.e(Constants.TAG, ste.getMessage());
                retryCount++;
            } catch (ConnectTimeoutException cte) {
                LogUtil.e(Constants.TAG, cte.getMessage());
                retryCount++;
            } catch (Exception e) {
                LogUtil.e(Constants.TAG, e.getMessage());
                retryCount = RETRY_COUNT;
            }

        }

    }

    public void addBitmapToCache(String url, Bitmap bitmap) {
        if (null != bitmap) {
            synchronized (imageCache) {
                imageCache.put(url, bitmap);
            }
        }
    }

    public Bitmap getBitmapFromCache(String url) {
        if (imageCache.isCached(url)) {
            return imageCache.get(url);
        }

        return null;
    }

    public class ImageCache extends WeakHashMap<String, Bitmap> {

        // WeakHashMap....add by gjican...
        private static final long serialVersionUID = 1L;

        public boolean isCached(String url) {
            return containsKey(url) && get(url) != null;
        }

    }

    /**
     * The actual AsyncTask that will asynchronously download the image.
     */
    private class BitmapDownloadTask extends AsyncTask<String, Void, Bitmap> {
        private String url;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapDownloadTask(ImageView imageView) {
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            url = params[0];
            return loadImage(url, 400, 300);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (null == bitmap) {
                if (null != mListener) {
                    mListener.onImageDownloadedFailedListener();
                }
            }

            if (isCancelled()) {
                bitmap = null;
                if (null != mListener)
                    mListener.onImageDownloadedFailedListener();
            }

            if (null != bitmap) {
                addBitmapToCache(url, bitmap);
            }

            if ((null != imageViewReference) && (null != bitmap)) {
                ImageView imageView = imageViewReference.get();
                imageView.setImageBitmap(bitmap);
                if (null != mListener) {
                    mListener.onImageDownloadedListener();
                }
                mListener = null;
            }
        }

    }
}
